package com.justgame.project.cloud.base.entity;

import lombok.SneakyThrows;
import org.springframework.lang.NonNull;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

@SuppressWarnings("all")
public final class StringEncrypt implements Serializable {
    private static final String SECRET = "#secret#";
    private String encryptedValue;

    public String getEncryptedValue() {
        return encryptedValue;
    }

    @SneakyThrows
    public StringEncrypt(@NonNull Object object){
        this.encryptedValue = String.valueOf(object);
    }

    private StringEncrypt(){}

    /**
     * 静态构造方法
     * @param encryptedString 已加密的字符串
     * @return 加密对象
     */
    public static StringEncrypt encryptedOf(String encryptedString){
        return new StringEncrypt(encryptedString);
    }

    /**
     * 静态构造方法
     * @param encryptedString 未加密的字符串
     * @return 加密对象
     */
    public static StringEncrypt originBy(String originString){
        return new StringEncrypt(Encrypt(originString));
    }

    /**
     * 解密
     * @param string
     * @return
     * @throws Exception
     */
    public String decrypt(String string) throws Exception {
        return decrypt(encryptedValue, string);
    }

    /**
     * 加密
     * @param string
     * @return
     */
    @SneakyThrows
    private static String Encrypt(String string){
        SecretKeySpec key = new SecretKeySpec(sha256(string), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encrypted = cipher.doFinal(SECRET.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 加密
     * @param string
     * @return
     * @throws Exception
     */
    private String encrypt(String string) throws Exception {
        return Encrypt(string);
    }

    /**
     * 解密
     * @param encryptedValue
     * @param string
     * @return
     * @throws Exception
     */
    private String decrypt(String encryptedValue, String string) throws Exception {
        SecretKeySpec key = new SecretKeySpec(sha256(string), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedValue));
        return new String(original, StandardCharsets.UTF_8);
    }

    private static byte[] sha256(String string) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        return digest.digest(string.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    @SneakyThrows
    public String toString() {
        return this.encryptedValue;
    }
}
